home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Libraries / VideoToolbox 97.08.16 / VideoToolboxSources / PrintfExit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-21  |  8.4 KB  |  276 lines  |  [TEXT/CWIE]

  1. /* 
  2. PrintfExit.c
  3.  
  4. PrintfExit(const char *format,...);
  5. is normally equivalent to calling printf and exit.
  6.  
  7. Lots of VideoToolbox routines, when they find a really grievous error, print out
  8. a message and exit. Having one routine that does both makes the code slightly
  9. neater, since the if statement then doesn't need braces. Furthermore, both of
  10. these functions, printf, and exit are liable to break in foreign environments,
  11. e.g. when running as a MEX resource under MATLAB. Now the problem is confined to
  12. this file, where it can be handled by conditional compilation.
  13.  
  14. Since PrintfExit is called only when we're near death, it seems prudent to make
  15. sure there's enough stack space before calling printf, which crashes if there's
  16. less than about 4500 byts of stack. Note that StackGrow() moves memory.
  17.  
  18. I've replaced all calls to exit() in the entire VideoToolbox by calls to
  19. PrintfExit().
  20.  
  21. StackGrow() is defined in VideoToolbox.h.
  22.  
  23. 3/4/97 dhb & dgp. There's a bunch of new code here to deal with the translation
  24. of \n to \r and \r to \n. This is necessary when we use THINK C to compile
  25. a MEX file, because THINK C and MATLAB use incompatible codes for newline and return. 
  26. To work, this uses #defines in VideoToolbox.h, something like the following:
  27.  
  28. #if MATLAB && THINK_C
  29.     #undef printf
  30.     #undef mexPrintf
  31.     #undef mexWarnMsgTxt
  32.     #undef mexErrorMsgTxt
  33.     #define printf Printf
  34.     #define mexPrintf Printf
  35.     #define mexWarnMsgTxt(s) mexWarnMsgTxt(TranslateEOL(s))
  36.     #define mexErrorMsgTxt(s) mexErrorMsgTxt(TranslateEOL(s))
  37. #end
  38.  
  39. With other compilers (e.g. Metrowerks CodeWarrior) the standard #defines in mex.h are fine,
  40. provided you set the compiler option "MPW newlines".
  41.  
  42. HISTORY:
  43. 2/20/93    dgp    Wrote it based on conversation with David Brainard.
  44. 7/9/93    dgp    Test MATLAB in #if instead of #ifdef.
  45. 9/12/93    dgp    Moved Required() to Require.c.
  46. 9/15/93    dgp    Added "const" to prototype.
  47. 6/7/95    dhb, gmb SIOUX stuff conditional on not MATLAB
  48. 9/27/95 dgp SIOUX stuff conditional on MAC_C
  49. 8/30/95    dhb updated for MATLAB 4 and 5.
  50. 1/18/97    dgp increased MATLAB temporary string buffer from 256 to 1024 bytes.
  51. 3/4/97    dhb    increased it again to 4096 bytes.
  52.         dhb added TranslateEOL routine.
  53. 3/5/97    dgp It's dangerous to assume we can get 4 KB from the stack, so we
  54.             instead allocate a scratch area with NewPtr.
  55. 3/15/97    dgp    psychTable->restoreScreensAtError.
  56. 3/17/97 dhb The inclusion of psych table means we need PsychLibSources.h too. Added.
  57. 3/17/97 dgp Call GetPsychTable only once, to avoid infinite loop.
  58. 3/28/97 dgp Use psychTable->restoreScreensA4 to restore A4 for that routine.
  59. 3/31/97 dgp Use psychTable->restoringScreensAtError.
  60. 4/15/97    dgp    SetPriority(0) if MATLAB.
  61. 4/17/97    dgp    Don't bother to SetPriority(0) if we already know that it's zero.
  62. 4/21/97    dgp    Deleted the obsolete commented-out restoreScreensAtError code.
  63. */
  64. #include "VideoToolbox.h"
  65. #include <stdarg.h>        /* for variable-number-of-argument macros */
  66. #if MATLAB
  67.     #include "PsychLibSources.h"
  68. #endif
  69.  
  70. static char *GetScratch(long bytes);
  71. static void DisposeScratch();
  72.  
  73. int PrintfExit(const char *format,...)
  74. {
  75.     va_list args;
  76.     int i;
  77.     long qD=0;
  78.   
  79.     #if MAC_C
  80.         #if __MWERKS__ && !MATLAB
  81.             SIOUXSettings.autocloseonquit=0;
  82.         #endif
  83.         /*
  84.         The main program may have changed the current device. Let's
  85.         restore the main device before doing the printf. Most Standard C libraries
  86.         on the Mac crash if you call printf and the current device is not the main
  87.         device. I've suggested to both Symantec and Metrowerks that their stdout console code
  88.         could easily take the precaution of ensuring that the MainDevice is the current device 
  89.         (to set & restore, if necessary, or at least not crash), 
  90.         but, last I checked, they took no heed.
  91.         */
  92.         Gestalt(gestaltQuickdrawVersion,&qD);
  93.         if(qD>=gestalt8BitQD)SetGDevice(GetMainDevice());
  94.         //if(StackSpace()<6000)StackGrow(6000-StackSpace());
  95.     #endif
  96.     #if !MATLAB
  97.         #if MAC_C
  98.             /* printf crashes if there's less than about 4500 bytes of stack space */
  99.             if(StackSpace()<5000){
  100.                 SysBeep(20);
  101.                 exit(EXIT_FAILURE);
  102.             }
  103.         #endif
  104.         va_start(args,format);
  105.         i=vfprintf(stdout,format,args);
  106.         va_end(args);
  107.         #if __MWERKS__
  108.             printf("Hit Command-Q to quit.\n");
  109.         #endif
  110.         exit(EXIT_FAILURE);
  111.     #else
  112.     {
  113.         char *s=GetScratch(4000);
  114.         
  115.         va_start(args,format);
  116.         i=vsprintf(s,format,args);
  117.         va_end(args);
  118.         #undef mexPrintf
  119.         if(strlen(s)+1>4000)mexPrintf("%s buffer overrun.\n\r",__FILE__);
  120.         {
  121.             PsychTable *psychTable=GetPsychTable();// defined in <PsychLibSources.h>
  122.             Boolean screensActive=0;
  123.  
  124.             if(psychTable!=NULL){
  125.                 if(psychTable->priority!=0){
  126.                     SetPriority(0);
  127.                     psychTable->priority=0;
  128.                 }
  129.             }else SetPriority(0);
  130.             ShowCursor();
  131.             s[2000-200-1]=0;
  132.             if(psychTable!=NULL){
  133.                 if(!psychTable->restoringScreensAtError && !psychTable->restoringScreensAtFlush){
  134.                     screensActive=psychTable->windowTableHead!=NULL;
  135.                     for(i=0;i<MAX_SCREENS;i++)screensActive |= psychTable->screenInfo[i].valid;
  136.                     // mexEvalString() always returns, even if an error occurred.
  137.                     if(screensActive){
  138.                         psychTable->restoringScreensAtError=1;
  139.                         strcpy(s+2000,s);
  140.                         mexEvalString("SCREEN('CloseAll')");    // Restore screens.
  141.                         strcpy(s,s+2000);
  142.                         psychTable->restoringScreensAtError=0;
  143.                     }
  144.                 }
  145.                 if(psychTable->restoringScreensAtError){
  146.                     memmove(s+200,s,strlen(s)+1);
  147.                     sprintf(s,"Double trouble! An error occurred while restoring screens to "
  148.                         "report another error.\n%s",s+200);
  149.                     psychTable->restoringScreensAtError=0;
  150.                 }
  151.                 if(psychTable->restoringScreensAtFlush){
  152.                     memmove(s+200,s,strlen(s)+1);
  153.                     sprintf(s,"An error occurred while restoring screens before MATLAB flushes SCREEN.mex.\n%s",s+200);
  154.                     psychTable->restoringScreensAtFlush=0;
  155.                 }
  156.             }else{
  157.                 static Boolean restoringScreensAtError=0;
  158.                 if(!restoringScreensAtError){
  159.                     restoringScreensAtError=1;
  160.                     // if we knew we were in SCREEN.mex we could skip the call to mexEvalString.
  161.                     // mexEvalString() always returns, even if an error occurred.
  162.                     strcpy(s+2000,s);
  163.                     mexEvalString("SCREEN('CloseAll')");    // Restore screens.
  164.                     strcpy(s,s+2000);
  165.                 }else{
  166.                     memmove(s+200,s,strlen(s)+1);
  167.                     sprintf(s,"Double trouble! An error occurred while restoring screens to "
  168.                         "report another error.\n%s",s+200);
  169.                 }
  170.                 restoringScreensAtError=0;
  171.             }
  172.         }
  173.         #undef mexErrMsgTxt
  174.         mexErrMsgTxt(TranslateEOL(s));    /* Ask MATLAB to report the error. */
  175.     }
  176.     #endif
  177.     return 0;                /* Can't get here */
  178. }
  179.  
  180. #if MATLAB
  181.     // Printf is used solely by calls to printf that are redefined as Printf so
  182.     // as to benefit from TranslateEOL processing.
  183.     // #define printf Printf
  184.  
  185.     int Printf(const char *format,...)
  186.     {
  187.         va_list args;
  188.         int i;
  189.         long qD=0;
  190.       
  191.         Gestalt(gestaltQuickdrawVersion,&qD);
  192.         if(qD>=gestalt8BitQD)SetGDevice(GetMainDevice());
  193.         {
  194.             char *s=GetScratch(4000);
  195.  
  196.             va_start(args,format);
  197.             i=vsprintf(s,format,args);
  198.             va_end(args);
  199.             #undef mexPrintf
  200.             if(strlen(s)+1>4000)mexPrintf("%s buffer overrun.\n\r",__FILE__);
  201.             mexPrintf("%s",TranslateEOL(s));
  202.         }
  203.         return i;
  204.     }
  205. #endif
  206.  
  207. /*
  208. ROUTINE: TranslateEOL
  209. PURPOSE:
  210.     Turn \n into \r conditional on THINK and MATLAB. This
  211.     deals with the incompatible newline conventions in MATLAB vs THINK C.
  212.  
  213.     Note the special case of being called by Printf or PrintfExit. The string
  214.     will be our scratch area. The string fits in the scratch area so sOut==string.
  215.     The translation will thus be done in place, which is ok.
  216. */
  217.     
  218. char *TranslateEOL(char *string) {
  219.     #if THINK_C
  220.         int i;
  221.         char *sOut;
  222.         static Boolean firstTime = 1;
  223.         static char map[256];
  224.         
  225.         if (firstTime) {
  226.             firstTime = 0;
  227.             AtExitToShell(&DisposeScratch);
  228.             for(i=0;i<256;i++)map[i]=i;
  229.             map['\n']='\r';
  230.             map['\r']='\n';
  231.         }
  232.         
  233.         // Translate into the scratch area.    
  234.         sOut=GetScratch(strlen(string)+1);
  235.         for(i=0;string[i]!=0;i++)sOut[i]=map[string[i]];
  236.         
  237.         // Return the translated string. Valid until the scratch area is reused.
  238.         return(sOut);
  239.     #else
  240.         return string;
  241.     #endif
  242. }
  243.  
  244. static char *trScratch = NULL;    // PRIVATE!! used only by GetScratch & DisposeScratch
  245.  
  246. static char *GetScratch(long bytes)
  247. {
  248.     // Allocate scratch space if not yet allocated or too small.
  249.     if(trScratch!=NULL && GetPtrSize(trScratch)<bytes){
  250.         DisposePtr(trScratch);
  251.         trScratch=NULL;
  252.     }
  253.     if(trScratch==NULL)trScratch=NewPtr(bytes);
  254.     if(trScratch==NULL) {
  255.         char s[128];
  256.  
  257.         sprintf(s,"%s: can't allocate %ld bytes.\n\r",__FILE__,bytes);
  258.         #if !MATLAB
  259.             #undef printf
  260.             printf("%s",s);
  261.             exit(EXIT_FAILURE);
  262.         #else
  263.             mexErrMsgTxt(s);
  264.         #endif
  265.     }
  266.     return trScratch;
  267. }
  268.  
  269. static void DisposeScratch()
  270. {
  271.     if(trScratch!=NULL){
  272.         DisposePtr(trScratch);
  273.         trScratch=NULL;
  274.     }
  275. }
  276.